#include "EstadoCliente.h"
#include <algorithm>
#include <vector>

#define CYAN "\033[0;36m"
#define LIGHT_CYAN "\033[1;36m"
#define RED "\033[31m"
#define LIGHT_RED "\033[1;31m"
#define GRAY "\033[1;30m"
#define WHITE "\033[1;37m"
#define CYAN_BACK "\033[0;46m"
#define LIGHT_CYAN_BACK "\033[1;46m"
#define RED_BACK "\033[0;41m"
#define LIGHT_RED_BACK "\033[1;41m"
#define WHITE_BACK "\033[1;44m"
#define NO_COLOUR "\033[0m"

//***************************ESTADO NEUTRAL*************************

EstadoCliente::EstadoCliente(Cliente* cl){cliente = cl; std::cout << "Comando: "<< std::flush;}

std::string EstadoCliente::prepararComando(std::string s){
	//Transformo a minusculas
	transform(s.begin(), s.end(), s.begin(), tolower);

	//Borro espacios en blanco
	while(s.size()>0)
		if(s[0] == ' ')
			s.erase(0,1);
		else break;
	return s;
}

void EstadoCliente::entradaTeclado(std::string comando){
	comando = prepararComando(comando);
	if(comando[0] == 'l') //Listar jugadores
		obtenerListaJugadores();
	else if(comando[0] == 'i'){ //Invito a un jugador
		int numero = atoi(comando.c_str()+1);
		invitar(numero);
	}
	else if(comando[0] == 'd'){ //Disparo
		char coordenadaX;
		int coordenadaY;
		bool error=false;
		int posicion;

		//Salteo espacios
		for(posicion=1;posicion<comando.size()&&comando[posicion]==' ';posicion++);

			if(posicion < comando.size() && isalpha(comando[posicion])){
				coordenadaX = comando[posicion];

				const char *string = comando.c_str()+posicion+1;
				char *final;

				coordenadaY = strtol(string, &final, 10);
				if(final == string || coordenadaY==0)
					//No es un numero
					error=true;
			}
			else error=true;

			if (error)
				std::cout << "La sintaxis es: d <cordenada x> <coordenada y>\n";
			else{
				disparar(coordenadaX-'a',coordenadaY-1);
			}
	}
	else if(comando[0] == 'p') //Mostrar tablero
		mostrarTablero();
	else if(comando[0] =='q') //Salgo/abandono
		desconectar();

	std::cout << "Comando: " << std::flush;
}

void EstadoCliente::desconectar()__PLACEHOLDER__;
void EstadoCliente::recibirDesconeccion(MensajeDesconectar &m)__PLACEHOLDER__;
void EstadoCliente::recibirListaJugadores(MensajeListaJugadores &m)__PLACEHOLDER__;
void EstadoCliente::obtenerListaJugadores()__PLACEHOLDER__;
void EstadoCliente::recibirInvitacion(MensajeInvitacion &m){}
void EstadoCliente::invitar(int jugador)__PLACEHOLDER__;
void EstadoCliente::mostrarTablero()__PLACEHOLDER__;
void EstadoCliente::recibirTablero(MensajeTablero &m)__PLACEHOLDER__;
void EstadoCliente::disparar(char x, char y)__PLACEHOLDER__;
void EstadoCliente::recibirDisparo(MensajeDisparo &m)__PLACEHOLDER__;
void EstadoCliente::recibirTurno()__PLACEHOLDER__;
void EstadoCliente::comenzarJuego(MensajeComenzarJuego &m)__PLACEHOLDER__;
void EstadoCliente::ganar()__PLACEHOLDER__;
void EstadoCliente::perder()__PLACEHOLDER__;


//***********************CONECTADO**********************************************

Conectado::Conectado(Cliente* cl):EstadoCliente(cl){}

void Conectado::entradaTeclado(std::string comando){
	comando = prepararComando(comando);
	if(comando[0] == 'm'){
		//Muestro las invitaciones pendientes
		if(cliente->invitaciones.size() == 0)
			std::cout << "No hay invitaciones pendientes.\n";
		else{
			std::list<int>::iterator it;
			std::cout << "Invitaciones pendientes: \n";
			for(it=cliente->invitaciones.begin();it!=cliente->invitaciones.end();it++)
				std::cout << *it << "\n";
		}
	}

	EstadoCliente::entradaTeclado(comando);
}

void Conectado::recibirListaJugadores(MensajeListaJugadores &m){
	if(m.getCantidad()>0){
		if(m.getJugando(0))
			std::cout << RED;
		else std::cout << CYAN;
		
		std::cout << "Jugador: " << m.getNombre(0) << ":" << m.getID(0) << "\n";

		std::cout << NO_COLOUR;
	}
}

void Conectado::obtenerListaJugadores(){
	MensajeGetJugadores m;
	cliente->enviarMensaje(m);
}

void Conectado::invitar(int jugador){
	MensajeInvitacion m(jugador);
	cliente->enviarMensaje(m);
}

void Conectado::recibirInvitacion(MensajeInvitacion &m){
	std::cout << "Recibiste una invitación para jugar. Aceptala para comenzar el juego.\n";
	cliente->invitaciones.remove(m.getFuente()); //evito duplicados
	cliente->invitaciones.push_back(m.getFuente());
}

void Conectado::desconectar(){
	cliente->finalizar();
	MensajeDesconectar desconeccion;
	cliente->enviarMensaje(desconeccion);
}

void Conectado::recibirDesconeccion(MensajeDesconectar &m){
	cliente->finalizar();
	std::cout << "Desconexion del server.\n";
}

void Conectado::comenzarJuego(MensajeComenzarJuego &m){
	std::cout << "Comenzando juego con " << m.getNombre() << "(" << m.getId() << ")\n";
	cliente->cambiarEstado(new PosicionandoBarcos(cliente));
}

//****************POSICIONANDO BARCOS****************************************

PosicionandoBarcos::PosicionandoBarcos(Cliente *cl):EstadoCliente(cl){
	std::cout << "¿Desea posicionar los barcos manual o automáticamente?(M/A)" << std::flush;
	respuesta=false; //Hasta que me contesten
}

void PosicionandoBarcos::entradaTeclado(std::string comando){
	comando = prepararComando(comando);

	if(!respuesta){
		if(comando[0] == 'a'){
			//posicionamiento automático de los barcos
			respuesta=true;
			srand(time(NULL));
			while(cliente->tablero.getCantidadBarcos() < MAX_BARCOS){
				int x = rand()%ANCHO_TABLERO;
				int y = rand()%ALTO_TABLERO;
				if(cliente->tablero.ubicarBarco(x,y)==0)
					std::cout << "Barco posicionado en: (" << x << "," << y << ")\n";
			}
			MensajeTablero m;
			Tablero aux;
			m.setDatos(cliente->tablero, aux);
			cliente->enviarMensaje(m);
			cliente->cambiarEstado(new EligiendoTurnos(cliente)); 
		}
		else if(comando[0]=='m'){
			respuesta=true;
			std::cout << "A continuación, ingrese las coordenadas de sus 10 barcos.\n";
		}

		return;
	}
	
	char coordenadaX;
	int coordenadaY;
	bool error;

	error = false;

	if(isalpha(comando[0])){
		coordenadaX = comando[0];
		const char *string = comando.c_str()+1;
		char *final;
			
		coordenadaY = strtol(string, &final, 10);
		if(final == string || coordenadaY==0)
			//No es un numero
			error=true;
	}
	else error=true;
	if (error){
		std::cout << "La sintaxis es: <cordenada x> <coordenada y>\n";
	}
	else{
		int x=coordenadaX-'a';
		int y=coordenadaY-1;
		if(cliente->tablero.ubicarBarco(x,y)==0)
			std::cout << "Barco posicionado en: (" << x << "," << y << ")\n";
		else
			std::cout << "Coordenada inválida o ya ocupada.\n";
	}

	if(cliente->tablero.getCantidadBarcos() >= MAX_BARCOS){
		MensajeTablero m;
		Tablero aux;
		m.setDatos(cliente->tablero, aux);
		cliente->enviarMensaje(m);
		cliente->cambiarEstado(new EligiendoTurnos(cliente)); 
	}
}

void PosicionandoBarcos::desconectar(){
	MensajeDesconectar desconeccion;
	cliente->enviarMensaje(desconeccion);
	cliente->cambiarEstado(new Conectado(cliente));
}

void PosicionandoBarcos::recibirDesconeccion(MensajeDesconectar &m){
	std::cout << "El otro jugador se desconectó.\n";
	cliente->cambiarEstado(new Conectado(cliente));
}


//***********************ELIGIENDO TURNOS**************************

EligiendoTurnos::EligiendoTurnos(Cliente* cl):EstadoCliente(cl){
	std::cout << "A continuación ingresar un número del 0 al 100. Este numero se utilizará para determinar el jugador que comienza la pratida.\n";
}

void EligiendoTurnos::entradaTeclado(std::string comando){
	int numero = atoi(comando.c_str());
	MensajeElegirTurno m(numero);
	cliente->enviarMensaje(m);
	cliente->cambiarEstado(new Jugando(cliente));
}

void EligiendoTurnos::desconectar(){
	MensajeDesconectar desconeccion;
	cliente->enviarMensaje(desconeccion);
	cliente->cambiarEstado(new Conectado(cliente));
}

void EligiendoTurnos::recibirDesconeccion(MensajeDesconectar &m){
	std::cout << "El otro jugador se desconectó.\n";
	cliente->cambiarEstado(new Conectado(cliente));
}

//***********************JUGANDO**********************************

Jugando::Jugando(Cliente *cl):EstadoCliente(cl){
	esperando = true;
	automatico=false;
	esperandoRevancha=false;
}

void Jugando::entradaTeclado(std::string comando){
	comando = prepararComando(comando);

	if(esperandoRevancha){
		if(comando[0] == 's')
			cliente->cambiarEstado(new PosicionandoBarcos(cliente));
		else
			desconectar();
		return;
	}
	if(comando == "auto"){
		automatico ^= 1;
	}

	EstadoCliente::entradaTeclado(comando);
}

void Jugando::disparar(char x, char y){
	if(esperando){
		std::cout << "No se puede disparar hasta que no se tenga el turno.\n";
		return;
	}
	MensajeDisparo m(x,y);
	cliente->enviarMensaje(m);
	mostrarTablero();
	esperando = true;
}

void Jugando::recibirDisparo(MensajeDisparo &m){
	mostrarTablero();
}

void Jugando::mostrarTablero(){
	MensajeGetTablero m;
	cliente->enviarMensaje(m);
}

void Jugando::recibirTablero(MensajeTablero &m){
	dibujarTableros(&m);
}

void Jugando::recibirTurno(){
	esperando = false;
	if(automatico){
		int x = rand()%ANCHO_TABLERO;
		int y = rand()%ALTO_TABLERO;
		disparar(x,y);
	}
}

void Jugando::dibujarTableros(MensajeTablero *m){
	std::cout << "\n";
	dibujarLinea(45);
	std::cout << "   ";
	dibujarLinea(45);
	std::cout << std::endl;
	for(int i=0;i<2;i++){
		std::cout << "|   |";
		for(char c='A';c<='J';c++){
			std::cout << " " << c << " |";
		}
		std::cout << "   ";
	}
	std::cout << "\n";

	std::vector<Tablero> jugador;
	Tablero t1,t2;
	m->getDatos(t1, t2);
	jugador.push_back(t1);
	jugador.push_back(t2);
	
	for(int j=0;j<ALTO_TABLERO;j++){
		dibujarLinea(45);
		std::cout << "   ";
		dibujarLinea(45);
		std::cout << std::endl;


		for(int k=0;k<2;k++){
			std::cout << "| " << j+1;
			(j+1<10)? 
				std::cout << " " :
				std::cout << "";

			int tablero = k;

			for(int i=0;i<ANCHO_TABLERO;i++){
				std::cout << "|";
				
				char c = jugador[tablero].getCasillero(i,j);
				switch(c){
				case AGUA: 
					std::cout <<  WHITE_BACK << "   " << NO_COLOUR;
					break;
				case BARCO:
					std::cout  << WHITE << WHITE_BACK << "~^~" << NO_COLOUR;
					break;
				case BARCO_HUNDIDO:
					std::cout << RED << WHITE_BACK << " X " << NO_COLOUR;
					break;
				case DISPARO:
					std::cout << CYAN  << WHITE_BACK << " o " << NO_COLOUR;
					break;
				default:
					std::cout << " ? ";
					break;
				}
			}
			std::cout << "|   ";
		}
		std::cout << "\n";

	}
	dibujarLinea(45);
	std::cout << "   ";
	dibujarLinea(45);
	std::cout << std::endl;

}

void Jugando::ganar(){
	std::cout << "Ganaste el juego\n";
	std::cout << "¿Queres jugar la revancha?(S/N)\n";
	esperandoRevancha=true;
	automatico=false;
}

void Jugando::perder(){
	std::cout << "Perdiste el juego\n";
	std::cout << "¿Queres jugar la revancha?(S/N)\n";
	esperandoRevancha=true;
	automatico=false;
}

void Jugando::desconectar(){
	MensajeDesconectar desconeccion;
	cliente->enviarMensaje(desconeccion);
	cliente->cambiarEstado(new Conectado(cliente));
}

void Jugando::recibirDesconeccion(MensajeDesconectar &m){
	std::cout << "El otro jugador se desconectó.\n";
	cliente->cambiarEstado(new Conectado(cliente));
}
